//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Controls;
using OpenLS.Core.Serialization;
using OpenLS.Drawing;
using OpenLS.Spreadsheet.Serialization;

namespace OpenLS.Spreadsheet.Drawing
{
    ///<summary>
    /// Anchor with reference to a single cell
    ///</summary>
    public class OneCellAnchor: Anchor
    {
        public OneCellAnchor(Worksheet worksheet, CellAddress cell): base (worksheet)
        {
            Cell = cell;
        }
        public OneCellAnchor (Cell cell): base (cell.Worksheet)
        {
            Contract.Requires(cell != null);
            this.Cell = cell.Address;
        }
        internal OneCellAnchor(Worksheet worksheet) : base(worksheet) { }
        

        public double Width
        {
            get { return Size.Width; }
            set
            {
                Contract.Requires(value >= 0);
                Size.Width = value;
                if (Content is ShapeBase)
                {
                    ShapeBase b = (ShapeBase)Content;
                    b.Width = value;
                }
                NotifyPropertyChanged("Width");
                NotifyPropertyChanged("ActualWidth");
            }
        }

        public double Height
        {
            get { return Size.Height; }
            set
            {
                Contract.Requires(value >= 0);
                Size.Height = value;
                if (Content is ShapeBase)
                {
                    ShapeBase b = (ShapeBase)Content;
                    b.Height = value;
                }
                NotifyPropertyChanged("Height");
                NotifyPropertyChanged("ActualHeight");
            }
        }

        /*public int Column
        {
            get { return From.Column; }
            set { From.Column = value; }
        }

        public int Row
        {
            get { return From.Row; }
            set { From.Row  = value; }
        }
        */
        private CellAddress cell;

        ///<summary>
        /// Get or set the cell used as anchor
        ///</summary>
        public CellAddress Cell
        {
            get { return cell; }
            set { cell = value;NotifyPropertyChanged("Cell"); }
        }

        Point _offset = new Point();
        ///<summary>
        /// Get or set the vertical offset from the cell
        ///</summary>
        public override double RowOffset
        {
            get { return _offset.Y; }
            set { _offset.Y = value; NotifyPropertyChanged("RowOffset"); }
        }

        ///<summary>
        /// Get or set the horizontal offset from the cell
        ///</summary>
        public override double ColumnOffset
        {
            get { return _offset.X; }
            set { _offset.X = value; NotifyPropertyChanged("ColumnOffset"); }
        }

        #region IOfficeXmlSerializable Members

        internal override void ReadXmlCore(ReadContext context)
        {
            using (ReadContext c = context.Read(SpreadsheetConstants.SpreadsheetDrawingNamespace + "oneCellAnchor"))
            {
                c.PassAttributes();
                Marker _from = c.ReadElementAs<Marker>("from");
                _offset = new Point(_from.ColumnOffset, _from.RowOffset);
                Cell = new CellAddress (_from.Row, _from.Column);
                ext = new PositiveSize2D();
                IOfficeXmlSerializableAs i = ext;
                i.ReadXmlAs("ext", c);
                Content = ReadContent(c);
                ClientData = c.ReadOptionalElement<AnchorClientData>(AnchorClientData.xmlName);
            }
        }

        internal override void WriteXmlCore(WriteContext context)
        {
            using (WriteContext c = context.Write(SpreadsheetConstants.SpreadsheetDrawingNamespace + "oneCellAnchor"))
            {
                Marker from_ = new Marker {Row = Cell.Row, Column = Cell.Column};
                from_.ColumnOffset = ColumnOffset;
                from_.RowOffset = RowOffset;
                c.WriteElementAs(from_, "from");
                c.WriteElementAs(Size, "ext");
                c.WriteElement(Content);
                c.WriteOptionalElement(ClientData);
            }
        }

        #endregion

        private PositiveSize2D ext ;

        public PositiveSize2D Size
        {
            get {
                Contract.Ensures(Contract.Result<PositiveSize2D>() != null);
                if (ext == null)
                ext = new PositiveSize2D();
                return ext;
        }
            set { ext = value; }
        }



        public override double ActualWidth
        {
            get { return Width ; }
            set { Width = value; }
        }

        public override double ActualHeight
        {
            get { return Height; }
            set { Height = value ; }
        }

        internal override void DragSideImp(double amount, Dock sideType)
        {
            switch (sideType)
            {
                case Dock.Left:
                    ColumnOffset += amount;
                    Width -= amount;
                    adjustAnchors();
                    break;
                case Dock.Top:
                    RowOffset += amount;
                    Height -= amount;
                    adjustAnchors();
                    break;
                case Dock.Right:
                    Width += amount; break;
                case Dock.Bottom:
                    Height += amount; break;
                default:
                    throw new NotSupportedException();
            }
        }

        internal override void DragImp(double x, double y)
        {
            ColumnOffset += x;
            RowOffset += y;
            adjustAnchors();
        }
        private void adjustAnchors()
        {
            Debug.WriteLine(string.Format("Adject anchor {0} {1} {2}", ColumnOffset, RowOffset, Cell.Label));
            while (Cell.Row > 0 && RowOffset < 0)
            {
                RowOffset += Worksheet.Rows[Cell.Row].ActualHeight;
                Cell = new CellAddress(Cell.Row - 1, Cell.Column);
            }
            while (Cell.Column > 0 && ColumnOffset < 0)
            {
                if (Worksheet != null) ColumnOffset += Worksheet.Columns[Cell.Column].ActualWidth;
                Cell = new CellAddress(Cell.Row, Cell.Column - 1);
            }
            while (Cell.Row < Worksheet.MaxRowIndex - 1 && RowOffset > Worksheet.Rows[Cell.Row].ActualHeight)
            {
                RowOffset -= Worksheet.Rows[Cell.Row].ActualHeight;
                Cell = new CellAddress(Cell.Row + 1, Cell.Column);
            }
            while (Cell.Column < Worksheet.MaxColumnIndex - 1 &&
                   ColumnOffset > Worksheet.Columns[Cell.Column].ActualWidth)
            {
                ColumnOffset -= Worksheet.Columns[Cell.Row].ActualWidth;
                Cell = new CellAddress(Cell.Row, Cell.Column + 1);
            }
            Debug.WriteLine(string.Format("End adjust anchor {0} {1} {2}", ColumnOffset, RowOffset, Cell.Label));
           

        }

    }
}
